home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Windows Expert
/
Windows Expert.iso
/
windownt
/
lpr10.zip
/
LPR.C
< prev
next >
Wrap
C/C++ Source or Header
|
1992-11-08
|
15KB
|
640 lines
/*
* lpr.c - Windows NT lpr
*
* by Eric W. Brown
* 28 October '92
*/
#include <windows.h>
#include <winbase.h>
#include <winsock.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/locking.h>
#include <io.h>
#include "lp.h"
/*
* #defines
*/
#define HOSTNAME_LEN (MAX_COMPUTERNAME_LENGTH + 1)
#define USERNAME_LEN (32 /* MAX_USERNAME_LENGTH */ + 1)
/*
* Global Variables
*/
int sockfd = -1;
char hostname[HOSTNAME_LEN];
char username[USERNAME_LEN];
char *printer = NULL;
char *server = NULL;
char *temp_dir = NULL;
char *class = NULL;
char *job = NULL;
char *title = NULL;
char filter = 'f';
int noburst = 0;
int debug = 0;
int dosfilter = 0;
int width = 0;
int copies = 1;
int indent = -1;
int tcp_initialized = 0;
int seqno;
FILE *cf_file = NULL;
char tmp_cfname[33] = "";
char tmp_dfname[33] = "";
char tmp_stdin_fname[33] = "";
/*
* Prototypes
*/
int usage();
void lpr_start_protocol();
void lpr_finish_protocol();
void lpr_print_file(char *filename, char *name);
void lpr_send_file(int fd, int length);
void lpr_send(char *buf, int cnt);
void lpr_check_ack();
void lpr_create_control_file(char *tmp_cfname);
void lpr_capture_stdin(char *fname);
long lpr_text_filelength(int fd);
void lpr_filter_dos(char *infname, char *outfname);
int lpr_get_seqno(char *seq_fname);
void lpr_crash(int report, char *fmt, ...);
#define NO_REPORT 0
#define REPORT_SOCKERR 1
#define REPORT_FILEERR 2
#define REPORT_ERR 3
int usage()
{
fprintf(stderr, "Usage: lpr [ -Pprinter ] [ -Sserver ] [ -#num ] [ -C class ] [ -J job ]\n");
fprintf(stderr, " [ -T title ] [ -i [ numcols ]] [ -wnum ] [ -pvcgdntlfhD ]\n");
fprintf(stderr, " [ -u ] [ -#n ] [ name ... ]\n");
fprintf(stderr, " -u : filter for unix (remove ^M and ^D characters)\n");
exit(1);
return 0;
} /* usage() */
void main(int argc, char **argv)
{
char *ptr;
long fileHandle;
struct _finddata_t fileinfo;
int length;
char filename[256];
/*
* Get environment variables:
* server, printer, hostname, username & temp_dir
*/
server = getenv("SERVER");
printer = getenv("PRINTER");
if (!printer)
printer = DEFAULT_PRINTER;
length = HOSTNAME_LEN;
if (!GetComputerName(hostname, &length) || length == 0)
lpr_crash(REPORT_ERR, "lpr: No hostname, name your computer!!!\n");
length = USERNAME_LEN;
if (!GetUserName(username, &length))
strncpy(username, hostname, USERNAME_LEN);
temp_dir = getenv("TEMP");
if (!temp_dir) {
fprintf(stderr, "lpr: TEMP environment variable not set.\n");
exit(1);
}
else if (_access(temp_dir, 06) < 0) {
fprintf(stderr, "lpr: TEMP directory, %s, does not exist or %s\n",
temp_dir, "invalid permissions");
exit(1);
} /* else */
/*
* Parse command line
*/
#define NEXT_ARG() (argc--, argv++, argc ? *argv : (char *)(usage(), NULL))
#define ARG_ARG() (strlen(*argv) == 2 ? NEXT_ARG() : (*argv) + 2)
while (argc > 1 && argv[1][0] == '-') {
NEXT_ARG();
switch(argv[0][1]) {
case 'P': printer = ARG_ARG(); break;
case 'S': server = ARG_ARG(); break;
case 'C': class = ARG_ARG(); break;
case 'J': job = ARG_ARG(); break;
case 'T': title = ARG_ARG(); break;
case 'p':
case 'v':
case 'c':
case 'g':
case 'd':
case 'n':
case 't':
case 'l': filter = argv[0][1]; break;
case 'f': filter = 'r'; break;
case 'h': noburst = 1; break;
case 'D': debug = 1; break;
case 'u': dosfilter = 1; break;
case 'i':
indent = (*argv[2] ? atoi(*argv + 2) : 8);
if (indent < 0 || indent > 255) {
fprintf(stderr, "lpr: %s: invalid indentation, %s",
*argv, "please keep it between 0 and 255.\n");
usage();
} /* if */
break;
case 'w':
if (sscanf(ARG_ARG(), "%d", &width) != 1) {
fprintf(stderr, "lpr: invalid width\n");
usage();
} /* if */
break;
case '#':
if (sscanf(ARG_ARG(), "%d", &copies) != 1) {
fprintf(stderr, "lpr: # of copies must be an integer.\n");
exit(1);
} /* if */
break;
default:
fprintf(stderr, "lpr: '%s' invalid option\n", *argv);
usage();
} /* switch */
} /* while argc */
/*
* Loop over remaining arguments, (Print these files ...)
*/
while (argc > 1) {
NEXT_ARG();
/* For unix compatibility, replace '/'s with '\'s */
ptr = *argv;
while(*ptr)
if (*ptr++ == '/')
ptr[-1] = '\\';
if ((fileHandle = _findfirst(*argv, &fileinfo)) != -1L) {
do {
if (!tcp_initialized)
lpr_start_protocol();
strcpy(filename, *argv);
if (ptr = strrchr(filename, '\\'))
ptr[1] = '\0';
else if (ptr = strrchr(filename, ':'))
ptr[1] = '\0';
else
filename[0] = '\0';
strcat(filename, fileinfo.name);
lpr_print_file(filename, filename);
} while (_findnext(fileHandle, &fileinfo) == 0);
_findclose(fileHandle);
}
else {
fprintf(stderr, "lpr: %s: Invalid file spec.\n", *argv);
if (tcp_initialized)
break;
else
exit(1);
} /* else */
} /* while argc */
/*
* See if we should take input from stdin
*/
if (!tcp_initialized) {
lpr_start_protocol();
sprintf(tmp_stdin_fname, "%s\\sin%03d.tmp", temp_dir, seqno);
lpr_capture_stdin(tmp_stdin_fname);
lpr_print_file(tmp_stdin_fname, "(standard input)");
unlink(tmp_stdin_fname);
} /* if */
/*
* Clean up
*/
if (tcp_initialized) {
lpr_finish_protocol();
closesocket(sockfd);
lp_tcp_shutdown();
fclose(cf_file);
unlink(tmp_cfname);
} /* if */
exit(0);
} /* main() */
void lpr_start_protocol()
{
char seq_fname[33];
char message[80];
/*
* Do a lookup in the printcap file if necessary
*/
if (!server)
if (!(server = lp_printcap_server_lookup(printer))) {
fprintf(stderr, "lpr: No server, %s, and no printer, %s, %s",
server, printer, "in printcap file!\n");
usage();
} /* if */
/*
* Initialize tcp
*/
if (lp_tcp_startup())
lpr_crash(REPORT_SOCKERR, "lpr: Couldn't initialize tcp/ip\n");
tcp_initialized = 1;
if (debug) fprintf(stderr, "lpr: Initialized TCP/IP\n");
/*
* Open a socket
*/
if ((sockfd = lp_tcp_open(server)) < 0)
lpr_crash(REPORT_SOCKERR, "lpr: Couldn't open connection to server, %s\n",
server);
if (debug) fprintf(stderr, "lpr: Connected to server, %s\n", server);
/*
* Get sequence number and increment it
*/
sprintf(seq_fname, "%s\\lpr.seq", temp_dir);
seqno = lpr_get_seqno(seq_fname);
/*
* Create control file
*/
sprintf(tmp_cfname, "%s\\cfA%03d.tmp", temp_dir, seqno);
lpr_create_control_file(tmp_cfname);
/*
* Tell LPD to receive a job
*/
sprintf(message, "%c%s\n", LPD_PRINT_JOB, printer);
lpr_send(message, strlen(message));
lpr_check_ack();
if (debug) fprintf(stderr, "lpr: Server is accepting job.\n");
} /* lpr_start_protocol() */
void lpr_finish_protocol()
{
int length;
char message[80];
/*
* Send control file receive message
*/
fflush(cf_file);
length = _filelength(_fileno(cf_file));
sprintf(message, "%c%d cfA%03d%s\n", LPD_RECEIVE_CONTROL_FILE,
length, seqno, hostname);
lpr_send(message, strlen(message));
lpr_check_ack();
/*
* Send control file
*/
if (debug) fprintf(stderr, "lpr: Sending control file to %s\n", server);
_lseek(_fileno(cf_file), 0, SEEK_SET);
lpr_send_file(_fileno(cf_file), length);
} /* lpr_finish_protocol() */
void lpr_print_file(char *filename, char *name)
{
static int file_count = 0;
static char *df_prefix = "df?";
char dfname[65];
int fd;
int length;
char message[80];
int i;
int is_text;
/*
* Create df filename
*/
if (file_count++ % 26 == 0)
df_prefix[2]++;
else if (file_count == 27)
df_prefix = "dfA@";
df_prefix[strlen(df_prefix) - 1]++;
sprintf(dfname, "%s%03d%s", df_prefix, seqno, hostname);
/*
* See if we need to make a temporary file
*/
if (dosfilter) {
sprintf(tmp_dfname, "%s\\%s%03d.tmp", temp_dir, df_prefix, seqno);
lpr_filter_dos(filename, tmp_dfname);
} /* if */
/*
* Add to control file
*/
if (width) fprintf(cf_file, "W%d\n", width);
if (indent != -1) fprintf(cf_file, "I%d\n", indent);
if (filter == 'p') fprintf(cf_file, "T%s\n", (title ? title : name));
for(i = 0; i < copies; i++)
fprintf(cf_file, "%c%s\n", filter, dfname);
fprintf(cf_file, "U%s\n", dfname);
fprintf(cf_file, "N%s\n", name);
/*
* Open the file
*/
is_text = (filter == 'f' || filter == 'p' || filter == 'r' || dosfilter);
fd = open(dosfilter ? tmp_dfname : filename,
O_RDONLY | (is_text ? O_TEXT : O_BINARY));
if (fd < 0)
lpr_crash(REPORT_FILEERR, "lpr: Couldn't open file, %s\n", filename);
/*
* Try to send a file
*/
length = (is_text ? lpr_text_filelength(fd) : filelength(fd));
sprintf(message, "%c%ld %s\n", LPD_RECEIVE_DATA_FILE, length, dfname);
lpr_send(message, strlen(message));
lpr_check_ack();
/*
* Send the actual file
*/
if (debug) fprintf(stderr, "lpr: Sending %s to %s@%s.\n", name, printer, server);
lpr_send_file(fd, length);
close(fd);
if (*tmp_dfname) {
unlink(tmp_dfname);
*tmp_dfname = 0;
} /* if */
} /* lpr_print_file() */
void lpr_send_file(int fd, int length)
{
int cnt;
char buf[1024];
/*
* Send the file
*/
while(length) {
cnt = min(length, 1024);
if ((cnt = read(fd, buf, cnt)) <= 0)
lpr_crash(REPORT_FILEERR, "lpr: Error reading file\n");
lpr_send(buf, cnt);
length -= cnt;
} /* while */
/*
* Send end mark & get acknowledgement
*/
sprintf(buf, "%c", LPD_END_TRANSFER);
lpr_send(buf, 1);
lpr_check_ack();
} /* lpr_send_file() */
void lpr_send(char *buf, int cnt)
{
if (send(sockfd, buf, cnt, 0) != cnt)
lpr_crash(REPORT_SOCKERR, "lpr: Error talking to server, %s\n", server);
} /* lpr_send() */
void lpr_check_ack()
{
char buf[80];
int len;
while(1) {
len = recv(sockfd, buf, 79, 0);
if (len <= 0)
lpr_crash(REPORT_SOCKERR, "lpr: Server not responding.\n");
switch(buf[0]) {
case LPD_OK:
return;
case LPD_ERROR:
lpr_crash(NO_REPORT, "lpr: Server error\n");
case LPD_NO_SPOOL_SPACE:
lpr_crash(NO_REPORT, "lpr: Unable to accept job at this time.\n%s",
"Not enough spool space on server.\n");
default:
/* An error message? */
buf[len] = 0;
fprintf(stderr, "%s", buf);
} /* switch */
} /* while */
} /* check_ack() */
void lpr_create_control_file(char *tmp_cfname)
{
/*
* Open the control file
*/
cf_file = fopen(tmp_cfname, "w+b");
if (!cf_file)
lpr_crash(REPORT_FILEERR, "lpr: Couldn't open file, %s\n", tmp_cfname);
/*
* Start building the control file
*/
fprintf(cf_file, "H%s\n", hostname);
fprintf(cf_file, "P%s\n", username);
if (!noburst) {
if (job)
fprintf(cf_file, "J%s\n", job);
fprintf(cf_file, "C%s\n", class ? class : hostname);
fprintf(cf_file, "L%s\n", username);
} /* if */
} /* lpr_create_control_file() */
void lpr_capture_stdin(char *fname)
{
char buf[1024];
int len;
int fd;
if (debug) fprintf(stderr, "lpr: Capturing stdin to '%s'\n", fname);
fd = open(fname, _O_CREAT | _O_WRONLY | _O_TRUNC | _O_BINARY, 0666);
if (fd < 0)
lpr_crash(NO_REPORT, "lpr: Error creating temporary file, %s\n", fname);
while((len = read(0, buf, 1024)) > 0)
if (_write(fd, buf, len) != len)
lpr_crash(NO_REPORT, "lpr: Error writing to tmp file, %s\n", fname);
close(fd);
} /* lpr_capture_stdin() */
int lpr_get_seqno(char *seq_fname)
{
int seqno;
int fd;
int cnt;
char buf[80];
/*
* Open the sequence file, if it doesn't exist, create it.
*/
if ((fd = _open(seq_fname, _O_RDWR | _O_CREAT | _O_TEXT)) < 0)
lpr_crash(REPORT_FILEERR, "lpr: Couldn't open (or create) sequence file (%s)\n",
seq_fname);
/*
* Lock the file (the first byte of it anyway)
*/
if (_locking(fd, _LK_LOCK, 1))
lpr_crash(REPORT_FILEERR, "lpr: Couldn't lock sequence file, %s\n", seq_fname);
/*
* Get the sequence number
*/
cnt = read(fd, buf, 79);
buf[cnt] = 0;
if (sscanf(buf, "%d", &seqno) != 1)
seqno = 1;
/*
* Write new sequence number
*/
_lseek(fd, 0, SEEK_SET);
sprintf(buf, "%03d\n", (seqno + 1) % 1000);
write(fd, buf, strlen(buf));
/*
* Unlock & close file
*/
_lseek(fd, 0, SEEK_SET);
_locking(fd, _LK_UNLCK, 1);
_close(fd);
return (seqno);
} /* lpr_get_seqno() */
void lpr_crash(int report, char *fmt, ...)
{
va_list marker;
if (fmt) {
va_start(marker, fmt);
vfprintf(stderr, fmt, marker);
va_end(marker);
} /* if */
if (tcp_initialized) {
if (sockfd != -1) closesocket(sockfd);
lp_tcp_shutdown();
if (cf_file) fclose(cf_file);
if (*tmp_dfname) unlink(tmp_dfname);
if (*tmp_stdin_fname) unlink(tmp_stdin_fname);
} /* if */
exit(1);
} /* lpr_crash() */
long lpr_text_filelength(int fd)
{
char buf[1024];
int length = 0;
int cnt;
/* Read the whole file */
while((cnt = read(fd, buf, 1024)) > 0)
length += cnt;
/* Rewind to the beginning */
lseek(fd, 0, SEEK_SET);
return length;
} /* lpr_text_filelength() */
void lpr_filter_dos(char *infname, char *outfname)
{
FILE *in_file;
FILE *out_file;
char buf[1024];
char *ptr;
if (debug) fprintf(stderr, "lpr: Filtering ^D's from '%s' to '%s'\n",
infname, outfname);
in_file = fopen(infname, "rt");
if (!in_file)
lpr_crash(REPORT_FILEERR, "lpr: Couldn't open file '%s'\n", infname);
out_file = fopen(outfname, "wt");
if (!out_file)
lpr_crash(REPORT_FILEERR, "lpr: Couldn't create file '%s'\n", outfname);
while(!feof(in_file)) {
/* Try to get one line of text */
fgets(ptr = buf, 1023, in_file);
/* Exclude lines that begin with ^D or ^Z */
if (buf[0] == 4 || buf[0] == 26)
if (*++ptr == '\n')
continue;
while(ptr[0] && !feof(in_file)) {
if (fputs(ptr, out_file) == EOF)
lpr_crash(REPORT_FILEERR, "lpr: Couldn't write to file '%s'\n",
outfname);
if (ptr[strlen(ptr) - 1] == '\n')
break;
fgets(ptr = buf, 1023, in_file);
} /* while */
} /* while */
fclose(in_file);
fclose(out_file);
} /* lpr_filter_dos() */